import com.cy.ActivityApplication;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 学生请假测试
 *
 * @author wxhn1
 * @since 2024-01-09 14:31
 */
@SpringBootTest(classes = ActivityApplication.class)
@Slf4j
public class 借支测试 {
	
	@Autowired
	RepositoryService ps;
	
	@Test
	public void 部署流程() {
		Deployment deploy = ps.createDeployment().addClasspathResource("借支申请.bpmn20.xml").deploy();
		System.out.println(deploy.getId());
	}
	
	
	@Autowired
	RuntimeService runtimeService;
	@Test
	public void 申请借支() {
		Map<String,Object> map = new HashMap<>();
		map.put("name","刚哥");
		// 根据流程定义的ID启动流程
		ProcessInstance instance = runtimeService.startProcessInstanceByKey("jz","jz1",map);
		// 查询此任务并继续
		Task task = taskService.createTaskQuery().processInstanceBusinessKey("jz1").singleResult();
		taskService.complete(task.getId());
		
	}
	
	
	@Autowired
	TaskService taskService;
	
	@Test
	public void 执行待审核的任务() {
		TaskQuery query = taskService.createTaskQuery();
		List<Task> taskList = query.
			processInstanceBusinessKey("jz1"). // 以业务id作为条件
//                processDefinitionKey("qj"). // 以流程id作为条件
//                taskAssignee("张三"). // 以任务办理人作为条件
	list();
		// 3.输出任务信息
		for (Task task : taskList) {
			System.out.println("任务ID:"+task.getId());
			System.out.println("任务名称:"+task.getName());
			System.out.println("任务的创建时间:"+task.getCreateTime());
			System.out.println("任务的办理人:"+task.getAssignee());
			System.out.println("流程实例ID："+task.getProcessInstanceId());
			System.out.println("执行对象ID:"+task.getExecutionId());
			System.out.println("流程定义ID:"+task.getProcessDefinitionId());
		}
	}
	
	
	//办理任务(主要操作ACT_RU_EXECUTION、ACT_RU_TASK表)
	@Test
	public void 办理任务() {
		// processInstanceBusinessKey 业务id
		// taskAssignee 任务处理人
		Task task = taskService.createTaskQuery().
			processInstanceBusinessKey("jz1")
//                .taskAssignee("刚哥")
			.singleResult();
		// 设置审批意见
		 taskService.addComment(task.getId(),task.getProcessInstanceId(),"同意");
		// 任务id 完成任务进入下一步
		Map<String, Object> map = new HashMap<>();
		map.put("sp", 1);
		map.put("money", 3500);
		taskService.complete(task.getId(), map);
	}
	
	
	
	@Autowired
	HistoryService historyService;
	/**
	 * 历史活动实例查询
	 */
	@Test
	public void queryHistoryTask() {
		List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery() // 创建历史活动实例查询
//                .processInstanceId("b6d83887-ad4b-11ee-b76f-005056c00008") // 执行流程实例id
			.processInstanceBusinessKey("jz1")  //根据业务id，查询当前业务下创建的流程实例
			.orderByTaskCreateTime()
			.asc()
			.list();
		for (HistoricTaskInstance hai : list) {
			System.out.println("活动ID:" + hai.getId());
			System.out.println("流程实例ID:" + hai.getProcessInstanceId());
			System.out.println("活动名称：" + hai.getName());
			System.out.println("办理人：" + hai.getAssignee());
			System.out.println("开始时间：" + hai.getStartTime());
			System.out.println("结束时间：" + hai.getEndTime());
			
			
			List<Comment> taskComments = taskService.getTaskComments(hai.getId());
			for (Comment taskComment : taskComments) {
				System.out.println("---"+taskComment.toString());
				System.out.println("审批意见:" + taskComment.getFullMessage());
			}
		}
	}
	
	
	@Test
	public void 根据业务id判断流程是否结束(){
		ProcessInstance pi = runtimeService.createProcessInstanceQuery().
			processInstanceBusinessKey("qj:10086").singleResult();
		System.out.println(pi==null?"结束":"未结束");
	}
	
	
	/**
	 * 查询历史流程变量
	 */
	@Test
	public void queryHisProVariable(){
		// 先根据流程id查询出历史任务
		HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().processInstanceBusinessKey("jz5")
			.list().get(0);
		
		// 查询出该任务执行中所有的变量
		List<HistoricVariableInstance> historicVariableInstanceList = historyService
			.createHistoricVariableInstanceQuery().
			processInstanceId(task.getProcessInstanceId()).list();
		
		boolean b = true;
		
		for(HistoricVariableInstance v: historicVariableInstanceList){
			if(v.getVariableName().endsWith("sp")){
				int sp = (int) v.getValue();
				if (sp == 0) {
					b = false;
					break;
				}
			}
		}
		
		System.out.println("(b?:\"\") = " + (b?"流程审批通过":"流程审批不通过"));
	}
	
	
	
	@Autowired
	RepositoryService repositoryService;
	
	@Test
	public void 流程图(){
		try {
			// 获取历史流程实例
			HistoricProcessInstance historicProcessInstance = historyService
				.createHistoricProcessInstanceQuery()
				.processInstanceBusinessKey("jz1").singleResult();
			// 获取流程中已经执行的节点，按照执行先后顺序排序
			List<HistoricActivityInstance> historicActivityInstances = historyService
				.createHistoricActivityInstanceQuery()
				.processInstanceId(historicProcessInstance.getId())
				.orderByHistoricActivityInstanceId()
				.asc().list();
			// 高亮已经执行流程节点ID集合
			List<String> highLightedActivitiIds = new ArrayList<>();
			int index = 1;
			for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
				// 用默认颜色
				highLightedActivitiIds.add(historicActivityInstance.getActivityId());
				index++;
			}
			ProcessDiagramGenerator processDiagramGenerator = null;
			// 使用默认的程序图片生成器
			processDiagramGenerator = new DefaultProcessDiagramGenerator();
			BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
			// 高亮流程已发生流转的线id集合
			List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances);
			// 使用默认配置获得流程图表生成器，并生成追踪图片字符流
			InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel,
				highLightedActivitiIds, highLightedFlowIds, "宋体","微软雅黑", "黑体");
			// 输出图片内容
			int byteSize = 1024;
			byte[] b = new byte[byteSize];
			OutputStream os = Files.newOutputStream(Paths.get("E:\\ATTPD\\activity\\src\\main\\resources\\a.svg"));
			int len;
			while ((len = imageStream.read(b, 0, byteSize)) != -1) {
				os.write(b, 0, len);
			}
			os.close();
		} catch (Exception e) {
		
		}
		
	}
	
	/**
	 * 获取已经流转的线
	 *
	 * @param bpmnModel
	 * @param historicActivityInstances
	 * @return
	 */
	private static List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
		// 高亮流程已发生流转的线id集合
		List<String> highLightedFlowIds = new ArrayList<>();
		// 全部活动节点
		List<FlowNode> historicActivityNodes = new ArrayList<>();
		// 已完成的历史活动节点
		List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();
		
		for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
			FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
			historicActivityNodes.add(flowNode);
			if (historicActivityInstance.getEndTime() != null) {
				finishedActivityInstances.add(historicActivityInstance);
			}
		}
		
		FlowNode currentFlowNode = null;
		FlowNode targetFlowNode = null;
		// 遍历已完成的活动实例，从每个实例的outgoingFlows中找到已执行的
		for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
			// 获得当前活动对应的节点信息及outgoingFlows信息
			currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
			List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
			
			/**
			 * 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转： 1.当前节点是并行网关或兼容网关，则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 2.当前节点是以上两种类型之外的，通过outgoingFlows查找到的时间最早的流转节点视为有效流转
			 */
			if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
				// 遍历历史活动节点，找到匹配流程目标节点的
				for (SequenceFlow sequenceFlow : sequenceFlows) {
					targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
					if (historicActivityNodes.contains(targetFlowNode)) {
						highLightedFlowIds.add(targetFlowNode.getId());
					}
				}
			} else {
				List<Map<String, Object>> tempMapList = new ArrayList<>();
				for (SequenceFlow sequenceFlow : sequenceFlows) {
					for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
						if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
							Map<String, Object> map = new HashMap<>();
							map.put("highLightedFlowId", sequenceFlow.getId());
							map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
							tempMapList.add(map);
						}
					}
				}
				
				if (!CollectionUtils.isEmpty(tempMapList)) {
					// 遍历匹配的集合，取得开始时间最早的一个
					long earliestStamp = 0L;
					String highLightedFlowId = null;
					for (Map<String, Object> map : tempMapList) {
						long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
						if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
							highLightedFlowId = map.get("highLightedFlowId").toString();
							earliestStamp = highLightedFlowStartTime;
						}
					}
					
					highLightedFlowIds.add(highLightedFlowId);
				}
				
			}
			
		}
		return highLightedFlowIds;
	}
	

}
